package com.sjy.utils;

/**
 * @program: MurmurHash3
 * @description:
 * @author: 智慧的苏苏
 * @create: 2025-09-04 15:03
 **/
public class MurmurHash3 {
    public static long hash64(byte[] data) {
        final long seed = 0xe17a1465;
        final int length = data.length;
        final int nblocks = length >> 3;

        long h1 = seed;

        // body
        for (int i = 0; i < nblocks; i++) {
            long k1 = getLittleEndianLong(data, i * 8);

            k1 *= 0xc6a4a7935bd1e995L;
            k1 ^= k1 >>> 47;
            k1 *= 0xc6a4a7935bd1e995L;

            h1 ^= k1;
            h1 *= 0xc6a4a7935bd1e995L;
        }

        // tail
        int tailStart = nblocks * 8;
        long k1 = 0;
        for (int i = length - 1; i >= tailStart; i--) {
            k1 <<= 8;
            k1 |= (data[i] & 0xff);
        }
        if (length > tailStart) {
            k1 *= 0xc6a4a7935bd1e995L;
            k1 ^= k1 >>> 47;
            k1 *= 0xc6a4a7935bd1e995L;
            h1 ^= k1;
        }

        // finalization
        h1 ^= length;
        h1 ^= h1 >>> 47;
        h1 *= 0xc6a4a7935bd1e995L;
        h1 ^= h1 >>> 47;

        return h1;
    }

    private static long getLittleEndianLong(byte[] data, int offset) {
        return ((long) data[offset] & 0xff)
                | (((long) data[offset + 1] & 0xff) << 8)
                | (((long) data[offset + 2] & 0xff) << 16)
                | (((long) data[offset + 3] & 0xff) << 24)
                | (((long) data[offset + 4] & 0xff) << 32)
                | (((long) data[offset + 5] & 0xff) << 40)
                | (((long) data[offset + 6] & 0xff) << 48)
                | (((long) data[offset + 7] & 0xff) << 56);
    }
}
